/*
 *  Copyright (c) 2012 - 2013 Gilles Dupeyrou 
 * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
 */
var version = "0.44";

// Generic DOM element creation
function createElement(p, type, className) {
  var e = document.createElement(type);
  if(p) p.appendChild(e);
  if (className != undefined) e.className = className;
  return e;
}

wme_addons = Class.extend ({
  init : function(){
    this.tb= $("#edit-buttons");
    this.buttons = [];

    this.logger = $('<div id="logger">')
		    .css('width','500')
		    .css('background-color','rgba(0, 0, 0, 0.6)')
		    .css('color', 'white')
		    .css('font-size', '15px')
		    .css('font-weight', 'bold')
		    .css('margin-left','auto')
		    .css('margin-right','auto')
		    .appendTo($('#toolbar'));
  },
  log : function(msg,delay){
    this.logger.append($('<div id="mylog">').append( new Date().toLocaleDateString()+" "+new Date().toLocaleTimeString()+" : "+msg));//.show().delay(5000).fadeOut(100);
    setTimeout(function(){$('#logger').children().first().remove();},delay?delay:5000);
  },
  add_menu_bt: function(id, icon){
    var myMenuBt = $('<div id='+id+'>')
	      .addClass("toolbar-button toolbar-submenu")
	      .addClass("toolbar-group-drawing")
	      .addClass("ItemInactive");
    if (typeof(icon)==="undefined"){
      icon = document["WME_Icon"].src;
    }
    myMenuBt.attr('style', 'width:60px;background:url('+icon+') no-repeat center, -moz-linear-gradient(top , #FFFFFF 0%, #FFFFFF 5%, #A7CFDC 100%);background:url('+icon+') no-repeat center, -webkit-gradient(linear, left top, left bottom, color-stop(0%,#FFFFFF), color-stop(5%,#FFFFFF), color-stop(100%,#A7CFDC))');
    myMenuBt.hover(function(){
      $(this).attr('style','width:60px;background: url('+icon+') no-repeat center, -moz-linear-gradient(top, #FFFFFF 0%, #FFFFFF 5%, #8EBCCC 100%);background: url('+icon+') no-repeat center,-webkit-gradient(linear, left top, left bottom, color-stop(0%,#FFFFFF), color-stop(5%,#FFFFFF), color-stop(100%,#8EBCCC))')
      },
      function(){
	$(this).attr('style', 'width:60px;background:url('+icon+') no-repeat center, -moz-linear-gradient(top , #FFFFFF 0%, #FFFFFF 5%, #A7CFDC 100%);background:url('+icon+') no-repeat center, -webkit-gradient(linear, left top, left bottom, color-stop(0%,#FFFFFF), color-stop(5%,#FFFFFF), color-stop(100%,#A7CFDC))');
      }
    );
    this.tb.width=parseInt(this.tb.css("width"))+2+(parseInt(this.tb.css("width"))/$(".toolbar-button",this.tb).length);
    this.tb.css("width", this.tb.width+"px");
    myMenuBt.menu = $('<menu class="submenu">');
    myMenuBt.append(myMenuBt.menu);
    this.tb.append(myMenuBt);
    this.buttons[id] = myMenuBt;
    return myMenuBt;
  },

  add_menu_entry: function(menu,title,callback,tooltip){  
    ret = $("<div>").addClass("drawing-toolbar-button ItemInactive").appendTo(menu).attr("title",tooltip).append("<span>"+title+"</span>").click(function(e) 
      {
	if(callback && typeof(callback) === "function") {
	  callback();
	}
      });
    return ret;
  },
  add_submenu_entry : function(menu, title, tooltip){
    ret = $("<div>").addClass("drawing-toolbar-button ItemInactive").attr("title",tooltip).attr("style","height:32px")
    .append("<span>"+title+"</span>")
    .hover(function() { $(this).children("div:first").show(); },
	   function() { $(this).children("div:first").hide(); }) 
    .appendTo(menu);
    $("<div id='submen'>")
      .addClass("drawing-toolbar-button ItemInactive")
      .attr("style","position: relative; bottom: "+ret.height().toString() +"px !important; left: "+ret.width().toString()+"px !important")
      .hide()
      .appendTo(ret);
    
    return ret;
  },
  add_submenu_item : function(submenu,title,callback, args, tooltip){
    submenu.children("div:first").append($("<div>")
    .addClass("drawing-toolbar-button ItemInactive")
    .attr("title",tooltip)
    .append("<span>"+title+"</span>")
    .click(function(e) 
      {
	if(callback && typeof(callback) === "function") {
	  callback(args);
	}
      }));
    
  },
});

var defOptions = {
  customLinks: {OSM:"http://www.openstreetmap.org/?lat=%lat%&lon=%lon%&zoom=(12+%zoom%)&layers=M",},
  alpha : 75,
  snapdst : 15,
  columns: ['Country', 'State', 'City', 'Street']
};

var toSave = {};
var o = localStorage.WMEAddons || '{}';
console.log("localStorage.WMEAddons: " + o);
o = JSON.parse(o);
for(var k in defOptions) toSave[k] = (typeof o[k] != 'undefined') ? o[k] : defOptions[k];
localStorage.WMEAddons = JSON.stringify(toSave);

$(window).bind('beforeunload', function(eventObject) {
    var returnValue = undefined;
    eventObject.returnValue = returnValue;
    localStorage.WMEAddons = JSON.stringify(toSave);
    console.log("localStorage.WMEAddons: " + localStorage.WMEAddons);
    return returnValue;
});

var  PossibleColumns = [
      'Country', 'State', 'City', 'StreetName', 'Street', 'StreetAlt', 'StreetId', 
      'Length', 'LockRank', 'Toll', 'Separator', 'level', 'roadTypeStr', 'CreatedBy', 'UpdatedBy', 'InLndMark', 'InScreen',
      'NbWays', 'RoundAbout', 'AllowNoDirection', 'FwdSpeed', 'RevSpeed'];

var RoadTypeString = {
 1: "Streets",
 2: "Primary Street",
 3: "Freeways",
 4: "Ramps",
 5: "Walking Trails",
 6: "Major Highway",
 7: "Minor Highway",
 8: "Dirt roads",
 10: "Pedestrian Bw",
 16: "Stairway",
 17: "Private Road",
 18: "Railroad",
 19: "Runway/Taxiway",
 20: "Parking Lot Road",
 21: "Service Road"
};

var RoadTypePriority = {
 0: 0,
 1: 1,
 2: 2,
 3: 3,
 4: 0,
 5: 0,
 6: 5,
 7: 4,
 8: .5,
 10: 0,
 16: 0,
 17: .7,
 18: 0,
 19: 0,
 20: .8,
 21: .6
};

function getSelectedLandMark(){
var lmList = []; 
  for(var i = 0; i < selectionManager.selectedItems.length; i++) {
    var m = selectionManager.selectedItems[i];
    if(m.type == Waze.Model.ObjectType.LANDMARK) lmList.push(m.geometry);
  }
  
  if(lmList.length == 0) {
    for(var id in wazeModel.landmarks.objects) {
      if(id < 0) {
        var curLm = wazeModel.landmarks.objects[id];
        var curFid;
        if(lmList.length == 0 || id < curFid) { lmList[0] = curLm.geometry; curFid = id; }
      }
    }
  }
  return lmList;
}
      
function getAddress(seg) {
  try{
        var f = seg.model.streets.get(seg.attributes.primaryStreetID), e, c, d, a, b = seg;
        if (f) {
            e = seg.model.cities.get(f.cityID);
            c = seg.model.states.get(e.stateID);
            d = seg.model.countries.get(e.countryID);
            a = seg.attributes.streetIDs.map(function(g) {
                b.model.streets.get(g)
            })
        }
        return {street: f,city: e,state: c,country: d,altStreets: a}
  }catch(err){
    addons.log("Error on getting attributes :"+err.message);
    return {street: "Error",city: "Error",state: "Error",country: "Error",altStreets: "Error"}
  }
}

function getStreetNameElt(streetName){
  if (!streetName){ return ['','']};
//  if (streetName.match(/^[ADRN]\d+\w?\b(?! ?:)/)){
  if (streetName.match(/^[ACDMN]\d{1,5}(?:(?:\w?\d?)|(?:[IXVLCDM]*))\b(?! ?:)/)){
//    r = [streetName.match(/^[ADRN]\d+\w?\b(?! ?:)/)[0],streetName.split(/-[!\s.]+/)[1]||''];
    r = [streetName.match(/^[ACDMN]\d{1,5}(?:(?:\w?\d?)|(?:[IXVLCDM]*))\b(?! ?:)/)[0],streetName.split(/-[!\s.]+/)[1]||''];
  }else {
    r = ['',streetName];
  }
  return r;
}

function getAttr(attr,seg){
  var x = '';
  var attrs = seg.getAddress();
  switch(attr){
    case 'Country':
      x = (Waze.Util.defined(attrs.country)&&Waze.Util.defined(attrs.country.name))?attrs.country.name:"";
      break;
    case 'countryID':
      x = attrs.country?attrs.country.id:"";
      break;
    case 'State':
      x = (Waze.Util.defined(attrs.state)&&Waze.Util.defined(attrs.state.name))?attrs.state.name:"";
      break;
    case 'stateID':
      x = attrs.state?attrs.state.id:"";
      break;
    case 'City':
      x = (Waze.Util.defined(attrs.city)&&Waze.Util.defined(attrs.city.name))?attrs.city.name:"";
      break;
    case 'cityID':
      x = attrs.city?attrs.city.id:"";
      break;
    case 'Street':
      x = (Waze.Util.defined(attrs.street)&&Waze.Util.defined(attrs.street.name))?attrs.street.name:"";
      break;
    case 'StreetName':
      st = getStreetNameElt(attrs.street?attrs.street.name:"")
      x = st[1];
      break;
    case 'StreetAlt':
      x = "Todo";
      break;
    case 'StreetId':
      st = getStreetNameElt((Waze.Util.defined(attrs.street)&&Waze.Util.defined(attrs.street.name))?attrs.street.name:"")
      x = st[0];
      break;
    case 'primaryStreetID':
      x = seg.attributes["primaryStreetID"]?seg.attributes["primaryStreetID"]:"Unknow";
      break;
    case 'Length':
      x = seg.attributes["length"]?seg.attributes["length"]:"Unknow";
      break;
    case 'LockRank':
      x = seg.attributes["lockRank"]?seg.attributes["lockRank"]:0;
      break;
    case 'Toll':
      x = (seg.attributes.fwdToll + seg.attributes.revToll) / 2;
      break;
    case 'Separator':
      x = seg.attributes["separator"]?seg.attributes["separator"]:"False";
      break;
    case 'level':
      x = seg.attributes["level"]?seg.attributes["level"]:"Unknow";
      break;
    case 'roadTypeStr':
      x = RoadTypeString[seg.attributes.roadType];
      break;
    case 'roadType':
      x = seg.attributes.roadType;
      break;
    case 'CreatedBy':
      x = "";
      var cb = seg.attributes.createdBy;
      if(cb > 0) {
	cb = wazeModel.users.objects[cb];
	if(cb!=null) x = cb.userName + ' (' + cb.normalizedLevel + ')';
      }
      break;
    case 'UpdatedBy':
      x = "";
      var cb = seg.attributes.updatedBy;
      if(cb > 0) {
	cb = wazeModel.users.objects[cb];
	if(cb!=null) x = cb.userName + ' (' + cb.normalizedLevel + ')';
      }
      break;
    case 'InLndMark':
      x = isInLanmarks(seg);
      break;
    case 'InScreen':
      var g = [wazeMap.getExtent().toGeometry(),];
      if(isSegmentInGeometries(g, seg, false)) return 1;
      if(!isSegmentInGeometries(g, seg, true)) return 0;
      x = 0.5;
      break;
    case 'NbWays':
      x = (seg.attributes.fwdDirection?1:0) + (seg.attributes.revDirection?1:0);
      break;
    case 'RoundAbout':
      x = seg.attributes.junctionID!=null;
      break;
    case 'AllowNoDirection':
      x = seg.attributes.allowNoDirection;
      break;
    case 'FwdSpeed':
      x = seg.attributes["fwdCrossSpeed"]?seg.attributes["fwdCrossSpeed"]:0;
      break;
    case 'RevSpeed':
      x = seg.attributes["revCrossSpeed"]?seg.attributes["revCrossSpeed"]:0;
      break;
  }
  return x;
}
		      
function mapModel(columns,segArray){
  var map = new Object();
    for(var i = 0;i<segArray.length;i++) {
      if (segArray[i].type == Waze.Model.ObjectType.SEGMENT){
	var maplvl = map;
	var seg = segArray[i];
	for(var j=0, len=columns.length; j < len; j++){
	  var key = getAttr(columns[j],seg);
	  var m = maplvl[key];
	  if (m ==null){
	    m = {} ;
	    maplvl[key] = m;
	  }
	  maplvl = m;
	}
	var lSt = maplvl[null];
	if(lSt == null) { lSt = new Array(); maplvl[null] = lSt; }
	lSt.push(seg);
      }else{addons.log("Warning : not a segment :"+id.toString());}
    }

  return map;
}

function fillTable(theTable,themap,cols){
  if (themap instanceof Array){
      if(themap.length > 0) {
        var seg = themap[0];
	trs = $('<tr border="1px solid #eee" padding=".6em 10px" text-align="left">');
        for(var j = 0; j < cols.length; j++) {
          var col = cols[j];
	  trs.append('<td>'+getAttr(col,seg)+'</td>');
        }
	trs.append($('<td>').append('<button style="width:50px">'+themap.length.toString()+'</button>').click(function(){selectionManager.select(themap)}));
        trs.append('</td></tr>');
	theTable.append(trs);
      }
  }else{    
    for(var colIdx in themap) {
	fillTable(theTable,themap[colIdx],cols);
    }
  }
}

function clearlist(segArray){
  dlg.refresh(segArray);
}

function segmentList(){
  if (typeof(dlg)==='undefined'){
    dlg = new lstdialog();
    dlg.opts.accordion({active:false});
  }
  dlg.refresh($.map(wazeModel.segments.objects,function(e,f){return e}));
  dlg.popup.dialog( "open" );
}

lstdialog = Class.extend({
  init : function(){
    this.popup = $(createElement(document.body, 'DIV', 'dialog-form')).css('font-size', '70.5%');
    this.opts = $('<div style="max-height:150px;overflow:auto;"><h5>Columns</h5>').accordion({
//	    icons : {header :'ui-icon-gear',activeHeader:'ui-icon-gear'},
            collapsible: true,
//	    active:false,
        }).attr('title','Select columns to display');
    var container = $('<div id="contain" style="display:table">');
    var col = [];
    col[0] = $('<div style="display:table-cell;width:20%">');
    col[1] = $('<div style="display:table-cell;width:20%">');
    col[2] = $('<div style="display:table-cell;width:20%">');
    col[3] = $('<div style="display:table-cell;width:20%">');
    col[4] = $('<div style="display:table-cell;width:20%">');
    for(var i = 0; i < PossibleColumns.length;){
      for (var j=0; j<col.length;j+=1){
	if (i < PossibleColumns.length){
	  var chk = $('<input type="checkbox" name="options[]" value="'+PossibleColumns[i]+'"/>').attr('checked',$.inArray(PossibleColumns[i],toSave.columns)>=0);
	  col[j].append($('<label style="font-size: 1em;margin-bottom: 5px;line-height: 3px;"/>').append(chk).append(PossibleColumns[i]));
	}
	i+=1;
      }
    }
    container.append(col);
    this.opts.append(container);
    this.slist = $('<div>');
    this.columns = toSave.columns;
    this.popup.append(this.tb);
    this.popup.append(this.opts);
    this.popup.append(this.slist);
    this.popup.dialog({
	title : "Segment list",
	autoOpen: false,
	height: 350,
	dialogClass: "seglist",
	width: 430,
	modal: false,
	buttons: {
	    Cancel: function() {
		$( this ).dialog( "close" );
	    }
	},
	close: function() {
	  toSave.columns.length = 0;
	  $("input[name='options[]']:checked").each(function(i){
	    toSave.columns.push(this.value);
	  });
	}
    });
    $('div.seglist').attr('style','position: absolute; top: 0; left: 0; padding: .2em; width: 300px; overflow: hidden;background:rgba(255, 255, 255, '+toSave.alpha/100+')');
    $('div.ui-dialog-titlebar',$('div.seglist'))
      .attr('style', 'height:10px;font-size:8px;line-height: 10px')
      .append($('<span height="10px">').button({icons : {primary :'ui-icon-refresh'}}).attr('title','Refresh whole segment list in the map')
      .click(function(e){
	clearlist($.map(wazeModel.segments.objects,function(e,f){return e}));
      }))
      .append($('<span height="10px">').button({icons : {primary :'ui-icon-calculator'}}).attr('title','Refresh selected segment list')
      .click(function(e){
	clearlist(selectionManager.selectedItems);
      }));
    $('div.ui-dialog-buttonpane').attr('style','height:25px;font-size:8px;line-height: 10px').last().append($('<div>').slider({
      value : toSave.alpha,
      change: function( event, ui ) {
	$('div.seglist').css('background','rgba(255, 255, 255,'+ui.value/100+')');
	toSave.alpha = ui.value;
      }
    }).attr('style','float:left;margin-top: 10px;width:50%').attr('title','Adjust background transparency'));
  },
  add_ToolBt : function(label,callback){
    this.tb.append($('<div>').append(label).button().click(function(e){
	  if(callback && typeof(callback) === "function") {
	    callback();
	  }
    }));
  },
  refresh : function(segArray){
    this.columns.length = 0;
    var cols = this.columns;
    $.each($("input[name='options[]']:checked"),function(){ cols.push(this.value);});
    this.slist.empty();
    if (wazeMap.getZoom()<=1){addons.log('Unapropriate Zoom level :'+wazeMap.getZoom().toString());return;}
    if (pendingControl.pending.length>0) {addons.log("WazeMap is refreshing, please wait");return;}
    var myTable =$('<table id="seg-list" border="1px solid #eee" margin="1em 0" padding="6em 10px" border-collapse="collapse" width="100%" text-align="left">');
    myHead = $('<thead>');
    myRow = $('<tr class="ui-widget-header" border="1px solid #eee" padding=".6em 10px" text-align="left">');
    $.each(cols,function(index,value){myRow.append('<td>'+value);});
    myRow.append('<td width="50px">Select');
    myHead.append(myRow);
    myBody = $('<tbody>');
    var mymap = mapModel(cols,segArray);
    fillTable(myBody,mymap,cols);
    myTable.append(myHead);
    myTable.append(myBody);
    this.slist.append(myTable);
    if (myTable.children()[1].childElementCount==0){
      myTable.append('<tr style="color:red; font-weight: bold; text-align:center !important"><td colspan=7 >The list is empty, try to zoom deeper or refresh the page...</td></tr>');
    }
    window.ts_makeSortable(myTable[0]);
  }  
});

function CSelectLandMark(strictInclude) {
  var geoList = [];
  
  for(var i = 0; i < selectionManager.selectedItems.length; i++) {
    var m = selectionManager.selectedItems[i];
    if(m.type == Waze.Model.ObjectType.LANDMARK) geoList.push(m.geometry);
  }
  
  if(geoList.length == 0) {
    for(var id in wazeModel.landmarks.objects) {
      if(id < 0) {
        var curLm = wazeModel.landmarks.objects[id];
        var curFid;
        if(geoList.length == 0 || id < curFid) { geoList[0] = curLm.geometry; curFid = id; }
      }
    }
  }
  
  if(geoList.length > 0) {
    var lSeg = new Array();
    for(var id in wazeModel.segments.objects) {
      var seg = wazeModel.segments.objects[id];
      if(isSegmentInGeometries(geoList, seg, !strictInclude))
        lSeg.push(seg);
    }
    
    selectionManager.select(lSeg);
  }
  else {
    addons.log("No new or selected landmark found");
  }
}

function isSegmentInGeometries(geoList, seg, partialAllowed) {
  for(var i = 0; i < seg.geometry.components.length; i++) {
    var p = seg.geometry.components[i];
    var found = false;
    for(var j = 0; j < geoList.length; j++) {
      var geo = geoList[j];
      if(geo.containsPoint(p)) {
        if(partialAllowed) return true;
        found = true;
        break;
      }
    }
    if(!partialAllowed && !found) return false;
  }
  return !partialAllowed;
}

function isInLanmarks(seg){
  var val = null;
  for(var i = 0; i < seg.geometry.components.length; i++) {
    var p = seg.geometry.components[i];
    var v = 0;
    var lnmLst = getSelectedLandMark();
    for(var j = 0; j < lnmLst.length; j++) {
      if(lnmLst[j].containsPoint(p)) { v=1; break; }
    }
    if(val == null) val = v;
    else if(val != v) return .5;
  }
  return val;
}

function CSuppressUnneededJunctions() {
  if (pendingControl.pending.length>0) {addons.log("WazeMap is refreshing, please wait");return;}
  var g = wazeMap.getExtent().toGeometry();
  var z = wazeMap.getZoom();
  if (z<4){
    addons.log("current zoom : "+z.toString());
    addons.log("You must increase your zoom level to perform this action");
    return;
  }

  var action = new Waze.Action.MultiAction();
  wazeModel.actionManager.add(action);
  for(var nodeID in wazeModel.nodes.objects) {
    var node = wazeModel.nodes.objects[nodeID];
    var ok = true;
    if(ok && node.state=="Delete") ok = false;
    if(ok && node.attributes.segIDs.length != 2) ok = false;
    if(ok && !node.isAllowed(node.PERMISSIONS.DELETE)) ok = false;
    if(ok && !g.containsPoint(node.geometry)) ok = false;
    if(ok) {
      var segs = node.attributes.segIDs.map(function(s){return wazeModel.segments.objects[s];});
      var attr0 = segs[0].attributes;
      var attr1 = segs[1].attributes;
      if(ok && attr0.junctionID!=null) ok = false;
      if(ok && attr1.junctionID!=null) ok = false;
      if(ok && attr0.primaryStreetID!=attr1.primaryStreetID) ok = false;
      if(ok && attr0.roadType!=attr1.roadType) ok = false;
      if(ok && attr0.locked!=attr1.locked) ok = false;
      if(ok) {
        var nodeID2 = attr0.fromNodeID==nodeID ? attr0.toNodeID : attr0.fromNodeID;
        if(nodeID2!=null)
          if(attr1.fromNodeID==nodeID2 || attr1.toNodeID==nodeID2)
            ok = false;
      }

      if(ok) {
//         segs.forEach(function(seg) {
//           var attr = seg.attributes;
//           if(!attr.locked && !attr.fwdDirection && !attr.revDirection)
//             setAttrs({ direction: 3 },new Array(seg));
//         });
        action.doSubAction(new Waze.Action.ModifyAllConnections(node, true));
        action.doSubAction(new Waze.Action.MergeSegments(null, node));
      }
    }
  }
}

function cleanRDBT(){
  if ((selectionManager.selectedItems.length != 1) ||(selectionManager.selectedItems[0].attributes.junctionID===null)){addons.log("You must select one segment which is part of a roundabout");return;}
  var seg = selectionManager.selectedItems[0];
  var jId = seg.attributes.junctionID;
  var junc = wazeModel.junctions.objects[jId];
  if (junc === null) {addons.log("Error detected when analysing this junction, try to refresh the page or rebuild this roundabout");return;}
  var lst = new Array();
  var lst2 = new Array();
  var attrs = {"countryID":null,"stateID":null,"cityID":null,"City":null,"roadType":0, "level":0};
  rdsegs = junc.segIDs;
  junc.segIDs.forEach(function(segID,idx){
    if (!wazeModel.segments.objects[segID]){
      addons.log("Unknow error parsing segments of the roundabout, rebuild it or retry with deeper zoom level!");
      return;
    }else{
      lst.push(wazeModel.segments.objects[segID]);
      wazeModel.nodes.objects[wazeModel.segments.objects[segID].attributes.fromNodeID].attributes.segIDs.forEach(function(segID,idx){
	if ($.inArray(segID,rdsegs)<0){
	  lst2.push(wazeModel.segments.objects[segID]);
	  if (wazeModel.segments.objects[segID].attributes['level']>attrs['level']) {attrs['level'] = wazeModel.segments.objects[segID].attributes['level'];}
          if(RoadTypePriority[wazeModel.segments.objects[segID].attributes['roadType']]>RoadTypePriority[attrs['roadType']]) {attrs['roadType'] = wazeModel.segments.objects[segID].attributes['roadType'];}
	  if (attrs['countryID']===null){ attrs['countryID'] = getAttr("countryID",wazeModel.segments.objects[segID]);}
	  if (attrs['stateID']===null){ attrs['stateID'] = getAttr("stateID",wazeModel.segments.objects[segID]);}
	  if (attrs['cityID']===null){ attrs['cityID'] = getAttr("cityID",wazeModel.segments.objects[segID]);}
	  if (attrs['City']===null){ attrs['City'] = getAttr("City",wazeModel.segments.objects[segID]);}
	}
      });
    }
  });
  attrs["level"] ++;
  attrs["locked"] = false;
  setAttrs(attrs,lst);

}

function setStreet(streetArray){
  if ((streetArray[0] != "")&&(streetArray[1] != "")){
    return streetArray.join(" - ");
  }else if (streetArray[0] != ""){
    return streetArray[0];
  }else if(streetArray[1] != ""){
    return streetArray[1];
  }else return "";
}

function setAddress(attrs,newAttrs,seg){
  var cntid,stID;
  if (attrs['countryID']){
    cntid = attrs['countryID']
  }else if (attrs['cityID']){
    cntid = wazeModel.cities.get(attrs['cityID']).countryID;
  }else if ((attrs['City'])&&(wazeModel.cities.getByAttributes({name:attrs['City']}).length>0)){
    cntid = wazeModel.cities.getByAttributes({name:attrs['City']})[0].countryID;
  }else if (getAttr('countryID',seg)){
    cntid  = getAttr('countryID',seg);
  }else{ //last, get from topCityID attribute of segment list in the map
    cntid = wazeModel.cities.get(wazeModel.segments.topCityID).countryID;
  }
  if (attrs['stateID']){
    stID = attrs['stateID']
  }else if (attrs['cityID']){
    stID = wazeModel.cities.get(attrs['cityID']).stateID;
  }else if ((attrs['City'])&&(wazeModel.cities.getByAttributes({name:attrs['City']}).length>0)){
    stID = wazeModel.cities.getByAttributes({name:attrs['City']})[0].stateID;
  }else if (getAttr('stateID',seg)){
    stID  = getAttr('stateID',seg);
  }else{
    stID = wazeModel.cities.get(wazeModel.segments.topCityID).stateID;
  }
  var ctname = attrs['City']? attrs['City']:getAttr('City',seg);
  var emptyct = (ctname==="");
  var fattr = {countryID : cntid,stateID : stID,isEmpty : emptyct};
  if (!emptyct){fattr.name=ctname}
  var ct = wazeModel.cities.getByAttributes(fattr);
  if (ct.length ===1){
    newAttrs['cityID'] = ct[0].getID();
  }else if (ct.length === 0){
    var f = new Waze.Action.CreateObject(Waze.Model.ObjectType.CITY, {
      countryID : cntid,
      stateID : stID,
      isEmpty: emptyct,
      name: ctname,
    });
    wazeModel.actionManager.add(f);
    newAttrs['cityID'] = f.newObject.getID();
    addons.log('Created new '+(emptyct?'empty ':'')+'city object '+attrs['City']);
  }else{
    addons.log('Abort : Multiple cities with same name on same country! please check');
    return false;
  }
  var st = getStreetNameElt(getAttr('Street',seg))
  if (attrs['StreetId']) {st[0] = attrs['StreetId']}
  if (attrs['StreetName']) {st[1] = attrs['StreetName']}
  if ((attrs['StreetId'])||(attrs['StreetName'])){
    newAttrs['Street'] = setStreet(st);
  } 

  return true;
}

function getOrCreateCity (attrs,seg){
}

function getOrCreateStreet(newAttrs,seg){
  var stname = newAttrs['Street']?newAttrs['Street']:getAttr('Street',seg);
  var emptyst = ((stname==null)||(stname==""))?true:false;
  var fattr = {cityID : newAttrs['cityID'],isEmpty:emptyst};
  if (emptyst==false){fattr.name=stname}
  var st = wazeModel.streets.getByAttributes(fattr);
  if (st.length === 1) {
    st = st[0];
  }else if (st.length === 0){
    addons.log('Info : Creating new street object...');
    var a = new Waze.Action.CreateObject(Waze.Model.ObjectType.STREET, {
                name : stname,
                isEmpty : emptyst,
                cityID : newAttrs['cityID']
              })
    wazeModel.actionManager.add(a);
    st = a.newObject;
  }else{
    addons.log('Aborted : Multiple streets with same name on same city, please check');
    return false;
  }
  newAttrs.primaryStreetID = st.getID();
  return true;
}

function setAttrs(attrs,segs){
  segs.forEach(function(seg){
    var newAttrs = jQuery.extend(true, {}, attrs);
    if (
	(seg.isLockedByHigherRank() === false)
	&&(seg.type == Waze.Model.ObjectType.SEGMENT)
	&&(seg.isAllowed(seg.PERMISSIONS.EDIT_PROPERTIES))
	&&(setAddress(attrs,newAttrs,seg)===true)
	&&(getOrCreateStreet(newAttrs,seg)===true)
      ){
	delete newAttrs.StreetName;
	delete newAttrs.StreetId;
	delete newAttrs.Street;
	delete newAttrs.countryID;
	delete newAttrs.stateID;
	delete newAttrs.cityID;
	delete newAttrs.City;
	var action = new Waze.Action.UpdateSegmentDetails(seg, newAttrs);
	wazeModel.actionManager.add(action);
    }
  });
}

function mapObj(obj,f) {
  return Object.values(obj).map(f).filter(function (i) { return i });
}

propertyDialog = Class.extend({
  init : function(){
      this.rows = ["City", "Street", "StreetId", "StreetName"];
      this.popup = $(createElement(document.body, 'DIV', 'PropertyDialog')).css('font-size', '70.5%');
      this.plist = $('<div>');
      this.popup.dialog({
	autoOpen: false,
	show: "fast",
	width: 330,
	height: 258,
	dialogClass: "propedit",
	title: "Properties editor",
	buttons: {
	    Cancel: function() {
		$( this ).dialog( "close" );
	    },
	    Apply: function() {
	      var attrs = {};
	      $.each($('input',this).filter(':checked'),function(id,val){
		attrs[val.name] = $('input[id='+val.name+']')[0].value;
	      });
	      setAttrs(attrs,selectionManager.selectedItems);
	    },
	},
      });
      this.popup.append(this.plist);
      $('div.propedit').attr('style','position: absolute; top: 0; left: 0; padding: .2em; width: 300px; overflow: hidden;background:rgba(255, 255, 255, '+toSave.alpha/100+')');
      $('div.ui-dialog-titlebar',$('div.propedit'))
	.attr('style', 'height:10px;font-size:8px;line-height: 10px')
	.append($('<span height="10px">').button({icons : {primary :'ui-icon-refresh'}}).attr('title','Refresh properties')
	.click(function(e){
	  refreshEdit();
	}));
      $('div.ui-dialog-buttonpane').attr('style','height:25px;font-size:8px;line-height: 10px').last().append($('<div>').slider({
	value : toSave.alpha,
	change: function( event, ui ) {
	  $('div.propedit').css('background','rgba(255, 255, 255,'+ui.value/100+')');
	  toSave.alpha = ui.value;
	}
      }).attr('style','float:left;margin-top: 10px;width:50%'));
  },
  refresh : function(){
    var cols = ["Edit","Attribute","Value"];
    var available = []
    available['Street'] = mapObj(wazeModel.streets.objects, _("name")).unique();
    available['City'] = mapObj(wazeModel.cities.objects, _("name")).unique();
    var rows = this.rows;
    this.plist.empty();
    var myTable =$('<table id="seg-list" border="1px solid #eee" margin="1em 0" padding=".6em 10px" border-collapse="collapse" width="100%" text-align="left">');
    var myHead = $('<thead>');
    var myRow = $('<tr class="ui-widget-header">');
    $.each(cols,function(index,value){myRow.append('<td>'+value);});
    myHead.append(myRow);
    myBody = $('<tbody>');
    var attrs = {};
    selectionManager.selectedItems.forEach(function(seg) {
      if (seg.type == Waze.Model.ObjectType.SEGMENT){
	$.each(rows, function(index,value){
	  var attr = getAttr(value,seg);
	  attrs[value] = (value in attrs && attrs[value]!=attr)?"Multiple":attr;
	});
      }
    });
    $.each(rows, function(index,value){
      var tr = $('<tr>');
      var inp =$('<input id='+value+' value="'+attrs[value]+'" style="width:99%"></input>').prop('disabled',true).autocomplete({source: available[value] }) ;
      var chk = $('<input name="'+value+'" type="checkbox"></input>').change(function(){
	$('#'+value).prop('disabled', !$(this).is(':checked'));
      });
      $('<td width="10px">').append(chk).appendTo(tr);
      tr.append('<td width="70px">'+value+'</td>');
      $('<td>').append(inp).appendTo(tr);
      myBody.append(tr);
    });
    myTable.append(myHead);
    myTable.append(myBody);
    this.plist.append(myTable);
  },
});

function refreshEdit(){
  dlgedt.refresh();
}

function PopupEdit(){
  if (typeof(dlgedt)==='undefined'){
    dlgedt = new propertyDialog();
  }
  if (selectionManager.selectedItems.length ==0){
    addons.log("No segment selected");
  }else{
    dlgedt.refresh();
    dlgedt.popup.dialog("open");
  }
}

function getUrlVars(href) {
    var vars = {}, hash;
    var idx = href.indexOf('?');
    var hashes = href.slice(idx + 1).split('&');
    vars[0] = href.slice(0, idx);
    for (var i = 0; i < hashes.length; i++) {
        hash = hashes[i].split('=');
        vars[hash[0]] = hash[1];
    }
    return vars;
}
function getCoord() {
  var mapLoc = localStorage.getItem("mapLocation");
  mapLoc = JSON.parse(mapLoc);
  var b = OpenLayers.Projection.transform({x : mapLoc.lon, y : mapLoc.lat },
        wazeMap.projection, wazeMap.displayProjection);
  mapLoc.lon = b.x;
  mapLoc.lat = b.y
  return mapLoc;
}

function openLiveMap(){
  var zoom = wazeMap.getZoom();
  href = $(livemap)[0].href;
   if(zoom >= 4) zoom = 9
   else if(zoom >=2) zoom += 5;
   else zoom += 6;
  window.open(href+"&zoom="+zoom);
}

function buildUrl(dic) {
  var href = [dic[0]];
  var first = true;
  for(var e in dic) {
    if(e!=0) {
      if(first) { href.push('?'); first = false; }
      else href.push('&');
      href.push(e, '=', dic[e]);
    }
  }
  return href.join('');
}

function openIn(lnk){
  var mapLoc = getCoord();
  var url = lnk.replace('%lat%',mapLoc.lat)
  url = url.replace('%lon%',mapLoc.lon)
  url = url.replace('%zoom%',mapLoc.zoom)
  var m  = url.match(/(?:\()(\w+\+\w+)(?:\){1})/);
  if (m&&m.length==2){
    res = m[1].split('+');
    if (res.length==2){
      val = parseInt(res[0])+parseInt(res[1]);
      url = url.replace(m[0],val);
    }
    
  } 
  window.open(url);
}

function storeLink(urlname,url){
  toSave['customLinks'][urlname]=url;
  addons.log("Link saved, refresh the page to load your changes");
}

function suppressLink(urlname){
  delete toSave['customLinks'][urlname];
  addons.log("Link deleted, refresh the page to load your changes");
}

linksDialog = Class.extend({
  init : function(){
    this.popup = $('<div>').appendTo($("body")).css('font-size', '70.5%');
    this.links = $('<div>');
    this.links.append('<div>Use %lat% for latitude %lon% for longitude and %zoom% for zoom level');
    this.links.append('<div>To add an offset value, put it in brackets with the + operator (eg: (12+%zoom%)');
    this.table = $('<table id="link-list" border="1px solid #eee" margin="1em 0" padding=".6em 10px" border-collapse="collapse" width="100%" text-align="left">');
    this.links.append(this.table);
    this.popup.dialog({
      autoOpen: false,
      show: "fast",
      width: 500,
      height: 258,
      dialogClass: "linksedit",
      title: "Configure links",
    });
    this.popup.append(this.links);
  },
  refresh : function(){
    this.table.empty();
  },
  addRow : function(lnkname,lnkstr){
    var myRow = $('<tr>');
    var myInputName = $('<td style="width:100px"><input id=urlname value="'+lnkname+'" style="width:99%">').appendTo(myRow);
    var myInputLink = $('<td><input id=url value="'+lnkstr+'" style="width:99%">').appendTo(myRow);
    
    var btAdd = $('<td style="width:30px">').append($('<button style="width:100%;height:100%" title="Save this entry">')
    .button({icons: {primary: 'ui-icon-disk'},text: false})
    .click(function(){
      storeLink($(this).parent().parent().children().find('#urlname')[0].value,$(this).parent().parent().children().find('#url')[0].value)
    })).appendTo(myRow);

    var btDel = $('<td style="width:30px">').append($('<button style="width:100%;height:100%" title="Delete this entry">')
    .button({icons: {primary: 'ui-icon-close'},text: false})
    .click(function(){
      suppressLink($(this).parent().parent().children().find('#urlname')[0].value)
    })).appendTo(myRow);
    
    var btTest = $('<td style="width:30px">').append($('<button style="width:100%;height:100%" title="Test your link">')
    .button({icons: {primary: 'ui-icon-link'},text: false})
    .click(function(){
      openIn($(this).parent().parent().children().find('#url')[0].value)  
    })).appendTo(myRow);
    
    myRow.appendTo(this.table);
  },
});

function editLinks(){
  if (typeof(dlglinks)==='undefined'){
    dlglinks = new linksDialog();
  }
  dlglinks.refresh();
  $.each(toSave['customLinks'],function(k,v){
    dlglinks.addRow(k,v);    
  });
  dlglinks.addRow("","");    
  dlglinks.popup.dialog("open");
  
//  dlglinks.addRow('Google Map','http://maps.google.com/maps?ll=%lat%,%lon%&z=(12+%zoom%)');
}

function initAddons(){
  addons = new wme_addons();
  addons.icon = document["WME_Icon"].src;
  var bt = addons.add_menu_bt("WME-Addons",document["WME_Icon"].src);
  addons.add_menu_entry(bt.menu,"Segment list",segmentList,"Show list of loaded segments on WazeMap with some filters");
  addons.add_menu_entry(bt.menu,"Properties",PopupEdit, "Edit properties of selected segments");
  var submenu = addons.add_submenu_entry(bt.menu,"Select in landmark >", "Select all segments inside the selected landmark");
  addons.add_submenu_item(submenu,"Large",CSelectLandMark,false, "Select all segments even partially in a landmark");
  addons.add_submenu_item(submenu,"Strict",CSelectLandMark,true, "Select all segments which are fully contained in a landmark");
  addons.add_menu_entry(bt.menu,"Clean Roundabout",cleanRDBT, "Set automatically many properties of all segments of a roundabout by selecting only one piece");
  var submenu = addons.add_submenu_entry(bt.menu,"Open in >", "Open same location on other maps");
  addons.add_submenu_item(submenu,"Edit links",editLinks);
  $.each(toSave['customLinks'],function(k,v){
    addons.add_submenu_item(submenu,k,openIn,v);    
  });
  addons.add_submenu_item(submenu,"Live Map",openLiveMap);
  addons.add_menu_entry(bt.menu,"Suppress extra junctions",CSuppressUnneededJunctions, "Suppress nodes which doesn't seem to be necessary on the whole current map");
  var mySpinner = addons.add_menu_entry(bt.menu,"",null);
  var tolerance = toSave.snapdst;
  var toleranceField;
  mySpinner.append($("<span style='text-align:left'>").append("Snap dist: "))
      .append($("<button style='width:20px;display:inline-block'>").append("<").click(function(e) { if(tolerance > 0) toleranceField.text(tolerance-=5);toSave.snapdst=tolerance; }))
      .append(toleranceField = $("<span style='width:3em;display:inline-block;'>").append(tolerance))
      .append($("<button style='width:20px;display:inline-block;'>").append(">").click(function(e) { toleranceField.text(tolerance+=5);toSave.snapdst=tolerance; }));
  addons.add_menu_entry(bt.menu,"About",About, "Display the current release of WME Addons");
  var user = loginManager.user;
  if (user !== null) {
    addons.log("Hello "+user.userName+" ("+user.normalizedLevel+")");
  }else{
    addons.log("Hello Stranger");
  }

  var testTargetOrig = Waze.Control.Snapping.prototype.testTarget;
  Waze.Control.Snapping.prototype.testTarget = function(tol,target) {
  var l = ["edgeTolerance", "nodeTolerance", "tolerance", "vertexTolerance"];
    for(var f in l) tol[l[f]] = tolerance;
      return testTargetOrig.call(this, tol, target);
  };
    
  wazeModel.cameras.minZoom = 0;
  var widthtomove =($("#sidebar").width()*100)/document.body.clientWidth;
  var sideoffset = (parseInt($("#sidebar").parent().parent().css('padding-left'))*100)/document.body.clientWidth;
  $('#sidebar').prepend('<div id="slider" title="Hide the side bar" style="float:right;background:rgba(0, 0, 0, 0.6);font-size: 100%;color:white;cursor: pointer;"><');
  $("#editor-container").css("position","absolute");
  $("#editor-container").css("width",(100-widthtomove-sideoffset)+"%");
  $('#slider').click(function(){slide()});
  
}
window.onresize = function(event) {
  var widthtomove =($("#sidebar").width()*100)/document.body.clientWidth;
  var sideoffset = (parseInt($("#sidebar").parent().parent().css('padding-left'))*100)/document.body.clientWidth;
  if ($("#sidebar").position().left>0){
//	  $("#editor-container").attr('style', function(i,s) { return s + 'max-width:'+(document.body.clientWidth-parseInt($("#sidebar").parent().parent().css('padding-left')))+'px;width:100%;' });
  }else{
//	  $("#editor-container").attr('style', function(i,s) { return s + 'max-width:'+(document.body.clientWidth-$("#sidebar").width()-parseInt($("#sidebar").parent().parent().css('padding-left')))+'px;width:100%;' });
  }
//  $("#editor-container").attr('style', function(i,s) { return s + 'max-width:'+(document.body.clientWidth-$("#sidebar").width()-parseInt($("#sidebar").parent().parent().css('padding-left')))+'px;' });
//  $("#editor-container").attr('style', function(i,s) { return s + 'max-width:6000px ;' });
//  addons.tb.width=parseInt(addons.tb.css("width"))+(parseInt(addons.tb.css("width"))/6);
//  addons.tb.css("width", addons.tb.width+"px");
}
function slide(){
  var widthtomove =($("#sidebar").width()*100)/document.body.clientWidth;
  var sideoffset = (parseInt($("#sidebar").parent().parent().css('padding-left'))*100)/document.body.clientWidth;
  if ($("#sidebar").position().left>0){
    $("#sidebar").animate({"left": "-="+(widthtomove)+"%"},100,function() {
	  $("#editor-container").css({left:+sideoffset+'%',width:(100-sideoffset)+'%'});
	});
    $('#slider').text('>');
  }else{
    $("#sidebar").animate({"left": "+="+(widthtomove)+"%"},100,function() {
	  $("#editor-container").css({left:(sideoffset+widthtomove)+'%',width:(100-widthtomove-sideoffset)+'%'});
	});
    $('#slider').text('<');
  }
}
// Check if jQuery's loaded
function wait_addons() {
  if((typeof jQuery.ui == 'undefined')||(typeof loginManager == 'undefined')) {
    window.setTimeout(wait_addons,100); 
  }else{
    initAddons();
    addons.log("WME Add-Ons V"+version+" loaded");
  }
}

function About(){
  $("<div align='center'>").attr("title","About")
  .append("<div>WME-Addons version: "+version)
  .append("<div> Copyright (c) 2012 - 2013 Gilles Dupeyrou ")
  .append("<div>Based on WME-Extended tools script")
  .append("<div>(https://waze-papyrus-extended-tools.googlecode.com)")
  .append("<div>Licensed under the MIT license")
  .append("<div> (http://www.opensource.org/licenses/mit-license.php).")
  .css('font-size', '60.5%')
  .dialog({width: 350,resizable:false});
}
  // Add jQuery
var JQ = document.createElement('script');
JQ.type = 'text/javascript';
JQ.src = "//ajax.googleapis.com/ajax/libs/jqueryui/1.9.2/jquery-ui.min.js";
JQ.onload =function(){
}
var ST_JQ = document.createElement('link');
ST_JQ.type = 'text/css';
ST_JQ.rel = 'stylesheet';
ST_JQ.href = "//ajax.googleapis.com/ajax/libs/jqueryui/1.9.2/themes/base/jquery-ui.css";
ST_JQ.onload =function(){
}
document.body.appendChild(JQ);
document.head.appendChild(ST_JQ);
wait_addons();
